<template>
  <div id="map" ref="map">
    <div id="mouse-position"></div>
    <el-button type="primary" class="btn" @click="onbtn">退回</el-button>
    <el-select v-model="value" placeholder="请选择" @change="qiehuan">
      <el-option
        v-for="item in options"
        :key="item.value"
        :label="item.label"
        :value="item.value"
      >
      </el-option>
    </el-select>
    <el-input
      placeholder="请输入地名"
      v-model="placename"
      class="input-with-select"
    >
      <el-button
        slot="append"
        icon="el-icon-search"
        @click="dingwei"
      ></el-button>
    </el-input>
    <div class="ceju">
      <el-button type="primary" @click="beginCalDistance">测距</el-button>
      <el-button type="primary" @click="cancleCalDistance">清除</el-button>
    </div>
  </div>
</template>

<script>
import axios from 'axios'
import 'ol/ol.css'
import TileLayer from 'ol/layer/Tile'
import OSM from 'ol/source/OSM'
import { Map, View } from 'ol'
// 导入地图控件
import { FullScreen, ZoomSlider, ScaleLine } from 'ol/control'
import MousePosition from 'ol/control/MousePosition'
import { format } from 'ol/coordinate'
import { XYZ, Vector as VectorSource, TileWMS } from 'ol/source'
import { Circle as CircleStyle, Fill, Stroke, Style } from 'ol/style'
import { Vector as VectorLayer } from 'ol/layer'
import GeoJSON from 'ol/format/GeoJSON'
import { fromLonLat } from 'ol/proj.js'
import Feature from 'ol/Feature'
import SourceVector from 'ol/source/Vector'
import { Select, Draw } from 'ol/interaction'
import { LineString } from 'ol/geom'
import Overlay from 'ol/Overlay'
import { getLength } from 'ol/sphere'

export default {
  data() {
    return {
      // 地图信息
      map: null,
      // 卫星影像
      tileSatellite: '',
      tdtLayer: '', // 天地地图
      maptar: '', // 地形图
      vectorLayer: '',
      vectorSource: {},
      draw: '',
      coordinate: [],
      lineSource: '', // 线的图层
      lineLayer: null,

      options: [
        {
          value: '1',
          label: '卫星影像'
        },
        {
          value: '2',
          label: '天地图'
        },
        {
          value: '3',
          label: '地形图'
        }
      ],
      value: '1', // 选择器
      placename: '' // 地名输入框
    }
  },
  mounted() {
    this.initMap()
  },
  methods: {
    initMap() {
      // const map = this.$refs.map
      this.map = new Map({
        target: 'map', // 指向对象
        layers: [
          // 图层
          new TileLayer({
            // 这里定义的是平铺图层
            source: new OSM()
          })
        ],
        view: new View({
          projection: 'EPSG:4326',
          center: [111.802482, 37.256177], // 中心坐标
          zoom: 12
        }),

        loadTilesWhileAnimating: true
      })
      // 加载天地图低图
      const source = new XYZ({
        url: 'http://t4.tianditu.com/DataServer?T=vec_w&tk=ad49c922e0359205a104835ec8d5a18d&x={x}&y={y}&l={z}'
      })
      this.tdtLayer = new TileLayer({
        title: '天地图',
        source
      })
      this.map.addLayer(this.tdtLayer)
      // 加载地图标注
      const Mark = new XYZ({
        url: 'http://t3.tianditu.com/DataServer?T=cva_w&tk=ad49c922e0359205a104835ec8d5a18d&x={x}&y={y}&l={z}'
      })
      const titlMark = new TileLayer({
        title: '标注',
        source: Mark
      })
      this.map.addLayer(titlMark)
      // 卫星图像
      const sourceSatellite = new XYZ({
        url: 'http://t3.tianditu.com/DataServer?T=img_w&tk=ad49c922e0359205a104835ec8d5a18d&x={x}&y={y}&l={z}'
      })
      this.tileSatellite = new TileLayer({
        source: sourceSatellite
      })
      this.map.addLayer(this.tileSatellite)
      // 天地图标注
      const mapcia = new TileLayer({
        title: '天地图标注',
        source: new XYZ({
          url: 'http://t4.tianditu.com/DataServer?T=cia_w&tk=ad49c922e0359205a104835ec8d5a18d&x={x}&y={y}&l={z}'
        })
      })
      this.map.addLayer(mapcia)
      // 天地图地形
      this.maptar = new TileLayer({
        title: '天地图地形',
        source: new XYZ({
          url: 'http://t4.tianditu.com/DataServer?T=ter_w&tk=ad49c922e0359205a104835ec8d5a18d&x={x}&y={y}&l={z}'
        })
      })
      this.map.addLayer(this.maptar)
      this.maptar.setVisible(false)
      const mapcta = new TileLayer({
        title: '天地图标注',
        source: new XYZ({
          url: 'http://t4.tianditu.com/DataServer?T=cta_w&tk=ad49c922e0359205a104835ec8d5a18d&x={x}&y={y}&l={z}'
        })
      })
      this.map.addLayer(mapcta)
      const mapwms = new TileLayer({
        source: new TileWMS({
          url: 'http://192.168.2.9:9080/geoserver/SDRS/wms',
          params: {
            LAYERS: 'SDRS:20210218_NDVI_SD',
            TILED: true
          }
        })
      })
      this.map.addLayer(mapwms)
      // 实时定位
      var image = new CircleStyle({
        radius: 5,
        fill: new Fill({
          color: 'rgba(255, 0, 0, 1)'
        }),
        stroke: new Stroke({ color: 'red', width: 2 })
      })

      var styles = {
        Point: new Style({
          image: image
        })
      }

      var styleFunction = function (feature) {
        return styles[feature.getGeometry().getType()]
      }
      // 定位坐标
      var geojsonObject = {
        type: 'FeatureCollection',
        features: [
          {
            type: 'Feature',
            geometry: {
              type: 'Point',
              coordinates: [111.802482, 37.256177]
            }
          }
        ]
      }

      this.vectorSource = new VectorSource({
        features: new GeoJSON().readFeatures(geojsonObject)
      })

      this.vectorLayer = new VectorLayer({
        source: this.vectorSource,
        style: styleFunction
      })
      this.map.addLayer(this.vectorLayer) // 定位的图层
      // 线的图层
      this.lineSource = new VectorSource({ wrapX: false })
      this.lineLayer = new VectorLayer({
        source: this.lineSource
      })
      this.map.addLayer(this.lineLayer) // 将线的图层添加
      // 缩放滑块刻度控件
      this.map.addControl(new ZoomSlider())
      // 比例尺控件
      this.map.addControl(new ScaleLine())
      // 地图全屏控件
      this.map.addControl(new FullScreen())
      // 鼠标悬停显示经纬度控件
      const mousePositionControl = new MousePosition({
        // 坐标格式
        coordinateFormat: function (coordinate) {
          return format(coordinate, '经度:{x} &nbsp; 纬度:{y}', 2)
        },
        // 地图投影坐标系（若未设置则输出为默认投影坐标系下的坐标）
        projection: 'EPSG:4326',
        // 坐标信息显示样式类名，默认是'ol-mouse-position'
        className: 'custom-mouse-position',
        // 显示鼠标位置信息的目标容器
        target: document.getElementById('mouse-position'),
        // 未定义坐标的标记
        undefinedHTML: '&nbsp;'
      })
      this.map.addControl(mousePositionControl)
    },
    onbtn() {
      // this.tileSatellite.setVisible(false)
      // 切换中心点
      this.map.getView().animate({
        // 只设置需要的属性即可
        center: [111.802482, 37.256177], // 中心点
        zoom: 12, // 缩放级别
        rotation: undefined, // 缩放完成view视图旋转弧度
        duration: 1000 // 缩放持续时间，默认不需要设置
      })
    },
    // 切换图层
    qiehuan() {
      if (this.value === '1') {
        // true 为关闭图层
        this.maptar.setVisible(false)
        this.tileSatellite.setVisible(true)
      } else if (this.value === '2') {
        this.maptar.setVisible(false)
        this.tileSatellite.setVisible(false)
      } else {
        this.maptar.setVisible(true)
      }
    },
    // 切换到输入城市的坐标
    dingwei() {
      axios({
        url:
          'http://api.tianditu.gov.cn/v2/search?postStr={"keyWord":"' +
          this.placename +
          '","level":12,"mapBound":"116.02524,39.83833,116.65592,39.99185","queryType":1,"start":0,"count":10}&type=query&tk=ad49c922e0359205a104835ec8d5a18d',
        method: 'get'
      }).then((res) => {
        this.map.getView().animate({
          // 只设置需要的属性即可
          center: res.data.area.lonlat.split(','), // 中心点
          zoom: 12, // 缩放级别
          rotation: undefined, // 缩放完成view视图旋转弧度
          duration: 1000 // 缩放持续时间，默认不需要设置
        })
      })
      // axios({
      //   url: 'https://api.obtdata.com/standard/searchcity',
      //   method: 'get',
      //   params: {
      //     code: '43'
      //   }
      // }).then((res) => {
      //   console.log(res.data)
      //   var source = new SourceVector({
      //     wrapX: false,
      //     code: 'EPSG:4326'
      //   })
      //   // ol.layer.Vector用于显示在客户端渲染的矢量数据。
      //   const vector = new VectorLayer({
      //     source: source
      //   })
      //   this.map.addLayer(vector)
      //   var geom = new GeoJSON().readGeometry(res.data.geom, {
      //     dataProjection: 'EPSG:4326',
      //     featureProjection: 'EPSG:3857'
      //   })
      //   console.log(geom)
      //   var feature = new Feature(geom)
      //   var sources = new SourceVector({
      //     features: [feature],
      //     wrapX: false
      //   })
      //   var polygons = sources.getFeatures()[0].getGeometry()
      //   var size = this.map.getSize()
      //   vector.getSource().addFeature(feature)
      //   // fit（geometryOrExtent，opt_options）根据给定的地图大小和边框拟合给定的几何或范围。
      //   this.map.getView().fit(polygons, size)
      // })
    },
    // 开始测距
    beginCalDistance() {
      // 调用绘图工具并传递类型为线，其他类型有Point,LineString,Polygon,Circle
      this.onAddInteraction('LineString')
      // 创建一个新的测距提示
      this.createMeasureTooltip()
    },
    // 绘图工具
    onAddInteraction(type) {
      let self = this
      // 勾绘矢量图形的类
      this.draw = new Draw({
        // source代表勾绘的要素属于的数据集
        source: self.lineSource,
        // type 表示勾绘的要素包含的 geometry 类型
        type: type
      })

      // 绘制开始时触发的事件
      this.draw.on('drawstart', function (evt) {
        self.sketch = evt.feature
        // 提示框的坐标
        var tooltipCoord = evt.coordinate
        // 定义一个事件监听，监听几何要素的change事件
        var listener = self.sketch.getGeometry().on('change', function (evt) {
          // 获取绘制的几何对象
          self.geom = evt.target
          // 定义一个输出对象，用于记录长度
          var output
          // 判断交互类型是否为线
          if (self.geom instanceof LineString) {
            // 输出多线段的长度
            output = self.formatLength(self.geom)
            // 获取多线段的最后一个点的坐标
            tooltipCoord = self.geom.getLastCoordinate()
          }
          // 设置测量提示框的内标签为最终输出结果
          self.measureTooltipElement.innerHTML = output
          self.measureTooltipElement.className =
            'ol-tooltip ol-tooltip-static draw_km'
          // 设置测量提示框的位置坐标
          self.measureTooltip.setPosition(tooltipCoord)
        })
      })

      // 绘制结束时触发的事件
      this.draw.on('drawend', function (e) {
        // 输出坐标信息
        const geometry = e.feature.getGeometry()
        const pointArr = geometry.getCoordinates()
        self.coordinate.push(pointArr)
        // 移除交互
        self.removeDraw()
      })

      // 添加交互
      self.map.addInteraction(this.draw)
    },
    // 创建一个新的测距提示
    createMeasureTooltip() {
      const self = this
      // 如果已经存在帮助提示框则移除
      if (self.measureTooltipElement) {
        self.measureTooltipElement.parentNode.removeChild(
          self.measureTooltipElement
        )
      }
      // 创建帮助提示要素的div
      self.measureTooltipElement = document.createElement('div')
      // 设置帮助提示要素的样式
      self.measureTooltipElement.className = 'ol-tooltip ol-tooltip-measure'
      // 创建一个帮助提示的覆盖标注
      self.measureTooltip = new Overlay({
        element: self.measureTooltipElement,
        offset: [0, -15],
        positioning: 'bottom-center'
      })
      // 将帮助提示的覆盖标注添加到地图中
      self.map.addOverlay(self.measureTooltip)
    },
    // 计算距离
    formatLength(line) {
      // 计算平面距离
      var length = Math.round(getLength(line) * 1000)
      // 定义输出变量
      var output
      // 如果长度大于1000，则使用km单位，否则使用m单位
      if (length > 100) {
        output = Math.round((length / 1000) * 100) + ' ' + 'km' // 换算成KM单位
      } else {
        output = Math.round(length * 100) + ' ' + 'm' // m为单位
      }
      return output
    },
    // 取消测距
    cancleCalDistance() {
      const self = this
      this.map.removeInteraction(this.draw)
      this.lineSource.clear()
      const layerArr = this.map.getOverlays()
      var deleteOverlayArr = []
      layerArr.forEach((item) => {
        if (
          item.values_.element.className ===
          'ol-tooltip ol-tooltip-static draw_km'
        ) {
          deleteOverlayArr.push(item)
        }
      })
      deleteOverlayArr.forEach((item) => {
        self.map.removeOverlay(item)
      })
    },
    // 删除交互
    removeDraw() {
      this.map.removeInteraction(this.draw)
    }
  }
}
</script>

<style>
#map {
  height: 100%;
  width: 100%;
  margin: 0;
  /* background-color: antiquewhite; */
}
#mouse-position {
  position: absolute;
  z-index: 20;
  left: 50%;
  transform: translateX(-50%);
  font-size: 20px;
  color: #fff;
  background-color: black;
}
.btn {
  position: fixed;
  z-index: 20;
  right: 100px;
  top: 0;
}
.el-select {
  position: fixed;
  left: 50px;
  z-index: 22;
}
.input-with-select {
  position: fixed;
  left: 300px;
  z-index: 20;
  width: 200px;
  height: 30px;
}
.ceju {
  position: fixed;
  right: 200px;
  z-index: 20;
  display: flex;
  justify-content: space-between;
}
.ol-tooltip {
  font-size: 22px;
  /* color: red; */
}
</style>
